
from collections import Counter
from collections import defaultdict

class SlopeOne(object):

    def __init__(self):
        self.diffs = {}
        self.freqs = {}

    def predict(self, userprefs):
        preds, freqs = {}, {}
        for item, rating in userprefs.iteritems():
            for diffitem, diffratings in self.diffs.iteritems():
                try:
                    freq = self.freqs[diffitem][item]
                except KeyError:
                    continue
                preds.setdefault(diffitem, 0.0)
                freqs.setdefault(diffitem, 0)
                preds[diffitem] += freq * (diffratings[item] + rating)
                freqs[diffitem] += freq
        return dict([(item, value / freqs[item])
        for item, value in preds.iteritems()
        if item not in userprefs and freqs[item] > 0])

    def update(self, userdata):
        for ratings in userdata.itervalues():
            for item1, rating1 in ratings.iteritems():
                self.freqs.setdefault(item1, {})
                self.diffs.setdefault(item1, {})
                for item2, rating2 in ratings.iteritems():
                    self.freqs[item1].setdefault(item2, 0)
                    self.diffs[item1].setdefault(item2, 0.0)
                    self.freqs[item1][item2] += 1
                    self.diffs[item1][item2] += rating1 - rating2
        for item1, ratings in self.diffs.iteritems():
            for item2 in ratings:
                ratings[item2] /= self.freqs[item1][item2]

def slope_one_filter(file_path, min_no_of_access_for_prediction, min_no_of_access_for_updation, no_of_predictions, training_sessions):

    s = SlopeOne()

    session_count = 0
    correct_no_of_predictions = 0
    total_no_of_predictions = 0

    # iterating through each session
    for line in open(file_path).read().splitlines():

        session_count += 1
        print session_count

        #prediction
        if session_count > training_sessions:

            session = line.split(',')
            if len(session) >= min_no_of_access_for_prediction:

                domain_ratings = defaultdict(int)
                no_of_accesses = 0

                top_predictions = []
                prev_domain = None

                for domain in session:

                    no_of_accesses += 1
                    domain_ratings[domain] += 1

                    if no_of_accesses >= min_no_of_access_for_prediction:

                        # updating the next predictions
                        predictions = s.predict(domain_ratings)
                        top_predictions = sorted(predictions, key=predictions.get, reverse=True)[:no_of_predictions]

                        if prev_domain != domain:
                            total_no_of_predictions += 1
                            if domain in top_predictions:
                                correct_no_of_predictions += 1

                        prev_domain = domain

        #updation
        session = line.split(',')
        if len(session) >= min_no_of_access_for_updation:

            # count the number of domains
            domain_ratings = defaultdict(int)
            for domain in session:
                domain_ratings[domain] += 1

            data = dict(
                this_is_not_important=domain_ratings
            )

            s.update(data)

    print 'Total number of predictions'
    print total_no_of_predictions
    print 'Correct number of predictions'
    print correct_no_of_predictions
    print 'Accuracy'
    print correct_no_of_predictions/total_no_of_predictions